/**
 * Title:       PlatformServiceManager.java
 * Copyright:   Copyright (c) 1996-2004 The Agent Factory Working Group. All rights reserved.
 * Licence:     This file is free software; you can redistribute it and/or modify
 *              it under the terms of the GNU Lesser General Public License as published by
 *              the Free Software Foundation; either version 2.1, or (at your option)
 *              any later version.
 *
 *              This file is distributed in the hope that it will be useful,
 *              but WITHOUT ANY WARRANTY; without even the implied warranty of
 *              MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *              GNU Lesser General Public License for more details.
 *
 *              You should have received a copy of the GNU Lesser General Public License
 *              along with Agent Factory; see the file COPYING.  If not, write to
 *              the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 *              Boston, MA 02111-1307, USA.
 */
package com.agentfactory.platform.service;

import com.agentfactory.platform.AgentPlatform;
import com.agentfactory.platform.core.Agent;
import com.agentfactory.platform.mts.MessageTransportService;
import com.agentfactory.platform.util.Logger;
import java.util.*;

/**
 * This class implements management functionality to support the activation of
 * multiple message transport services on a single agent platform.
 *
 * TODO - robertr - 13-Aug-2004 - Rem, is a factory initialisation needed for
 * the manager itself?
 *
 * TODO - robertr - 13-Aug-2004 - Should this class, along with the other service
 * classes be added into the main Agent Factory platform. Otherwise, should all
 * agent management system stuff be removed from the agent factory platform, and
 * just kept as a plugin.
 *
 * @author  Rem Collier
 */
public class PlatformServiceManager extends Observable {
    public static final int CLASS_LOG_LEVEL = Logger.LEVEL_ERROR;
    
    private Hashtable services;
    private ArrayList serviceList;
    private AgentPlatform agentPlatform;
    
    /**
     * Factory method that returns a message transport manager instance.
     */
    public static PlatformServiceManager newInstance(AgentPlatform agentPlatform) {
        return new PlatformServiceManager(agentPlatform);
    }
    
    /**
     * Factory method that returns a message transport manager instance.
     */
    public static PlatformServiceManager newInstance(Vector descriptors, AgentPlatform agentPlatform) {
        PlatformServiceManager manager = new PlatformServiceManager(agentPlatform);
        PlatformServiceDescriptor descriptor = null;
        for (int i = 0; i < descriptors.size(); i++) {
            descriptor = (PlatformServiceDescriptor) descriptors.elementAt(i);
            manager.addService(descriptor);
        }
        
        return manager;
    }
    
    /**
     * Constructor that initialises the message Transports array
     */
    private PlatformServiceManager(AgentPlatform agentPlatform) {
        services = new Hashtable();
        serviceList = new ArrayList();
        this.agentPlatform = agentPlatform;
    }
    
    /**
     * Registers a FIPA message transport service with the manager, which
     * in turn starts the service.
     *
     * @param inService the message transport service to be registered.
     */
    public void addService(PlatformService inService) {
        this.services.put(inService.getName(), inService);
        
        // Adding the service based on priority
        int i = 0;
        while (i < serviceList.size() && (((PlatformService) serviceList.get(i)).getPriority() >= inService.getPriority())) {
            i++;
        }
        serviceList.add(i, inService);
        
        inService.start();
    }
    
    /**
     * Second method that allows the class name (in string form) to be used
     * to add a FIPA message transport service.  This method creates an
     * instance of the service, and delegates the other addMessageTransport
     * method.
     *
     * @param descriptor a descriptor for the message transport service to be
     * created.
     */
    public void addService(PlatformServiceDescriptor descriptor) {
        Class theClass = null;
        try {
            theClass = Class.forName(descriptor.getClassName());
            PlatformService service = (PlatformService) theClass.newInstance();
            service.setName(descriptor.getName());
            service.init(descriptor, this);
            addService(service);
            setChanged();
            notifyObservers(service);
        } catch (ClassNotFoundException cnfe) {
            Logger.error("Failed to find service implementation: " +
                    descriptor.getClassName(), CLASS_LOG_LEVEL);
        } catch (InstantiationException ie) {
            Logger.error("Failed to Instantiate Service [" +
                    descriptor.getName() + "]", CLASS_LOG_LEVEL);
        } catch (IllegalAccessException iae) {
            Logger.error("Failed to Instantiate Service [" +
                    descriptor.getName() + "]", CLASS_LOG_LEVEL);
        }
    }
    
    public void removeService(String id) {
        PlatformService service = (PlatformService) services.remove(id);
        service.stop();
        setChanged();
        notifyObservers(service);
    }
    
    /**
     * Method used to shtudown all Message Transport Services registered to
     * this MessageTransportManager
     */
    public void shutdown() {
        Enumeration e = services.keys();
        while (e.hasMoreElements()) {
            ((PlatformService) services.get(e.nextElement())).stop();
        }
        services = new Hashtable();
    }
    
    public PlatformService bindToService(String name, Agent agent) {
        if (!agentPlatform.getSecurityModule().hasAccess(agent.getName(), name)) {
            //System.out.println("[PlatformServiceManager] Access to '" + name + "' denied for '" + agent.getName() + "'");
            return null;
        }

        PlatformService service = (PlatformService) services.get(name);
        if (service != null) {
            service.bind(agent);
        }
        
        return service;
    }
        
    public String getPlatformName() {
        return agentPlatform.getName();
    }
    
    public AgentPlatform getAgentPlatform() {
        return agentPlatform;
    }
    
    public ArrayList getServiceNames() {
        ArrayList list = new ArrayList();
        
        Iterator it = serviceList.iterator();
        while (it.hasNext()) {
            list.add(((PlatformService) it.next()).getName());
        }
        
        return list;
    }
    
    public PlatformService getService(String name) {
      return (PlatformService) services.get(name);
    }
    
    public String getServiceType(String name) {
        String type = null;
        PlatformService service = getService(name);
        
        if (service.getName().equals(name)) {
            type = service.getClass().getName();
        }
        
        return type;
    }
    
   public PlatformService getService(String name, AgentPlatform platform) {
        return getService(name);
   }
   
   public ArrayList getAvailableMTS(String name) {
        ArrayList list = new ArrayList();
        
        PlatformService service = null;
        Iterator it = serviceList.iterator();
        while (it.hasNext()) {
            service = (PlatformService) it.next();
            if (service instanceof MessageTransportService) {
                list.add(service.getName());
            }
        }
        
        return list;
   }
}
